﻿using System;
using System.Collections.Generic;
using System.Text;

namespace LumiSoft.Net.ABNF
{
    /// <summary>
    /// This class represent ABNF "dec-val". Defined in RFC 5234 4.
    /// </summary>
    public class ABNF_DecVal : ABNF_Element
    {
        #region enum ValueType

        private enum ValueType
        {
            Single = 0,
            Concated = 1,
            Range  = 2,
        }

        #endregion

        /// <summary>
        /// Default 'range' value constructor.
        /// </summary>
        /// <param name="start">Range start value.</param>
        /// <param name="end">Range end value.</param>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public ABNF_DecVal(int start,int end)
        {
            if(start < 0){
                throw new ArgumentException("Argument 'start' value must be >= 0.");
            }
            if(end < 0){
                throw new ArgumentException("Argument 'end' value must be >= 0.");
            }

            // TODO:
        }

        /// <summary>
        /// Default 'concated' value constructor.
        /// </summary>
        /// <param name="values">Concated values.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>values</b> is null reference value.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        public ABNF_DecVal(int[] values)
        {
            if(values == null){
                throw new ArgumentNullException("values");
            }
            if(values.Length < 1){
                throw new ArgumentException("Argument 'values' must contain at least 1 value.");
            }

            // TODO:
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static ABNF_DecVal Parse(System.IO.StringReader reader)
        {
            if(reader == null){
                throw new ArgumentNullException("reader");
            }

            // dec-val =  "d" 1*DIGIT [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]

            if(reader.Peek() != 'd'){
                throw new ParseException("Invalid ABNF 'dec-val' value '" + reader.ReadToEnd() + "'.");
            }

            // Eat 'd'.
            reader.Read();

            if(!char.IsNumber((char)reader.Peek())){
                throw new ParseException("Invalid ABNF 'dec-val' value '" + reader.ReadToEnd() + "'.");
            }

            ValueType     valueType = ValueType.Single;
            List<int>     values    = new List<int>();
            StringBuilder b         = new StringBuilder();
            while(true){
                // We reached end of string.
                if(reader.Peek() == -1){
                    // - or . without required 1 DIGIT.
                    if(b.Length == 0){
                        throw new ParseException("Invalid ABNF 'dec-val' value '" + reader.ReadToEnd() + "'.");
                    }
                    break;
                }
                else if(char.IsNumber((char)reader.Peek())){
                    b.Append((char)reader.Read());
                }
                // Concated value.
                else if(reader.Peek() == '.'){
                    // Range and conacted is not allowed to mix.
                    if(valueType == ValueType.Range){
                        throw new ParseException("Invalid ABNF 'dec-val' value '" + reader.ReadToEnd() + "'.");
                    }
                    if(b.Length == 0){
                        throw new ParseException("Invalid ABNF 'dec-val' value '" + reader.ReadToEnd() + "'.");
                    }

                    values.Add(Convert.ToInt32(b.ToString()));
                    b = new StringBuilder();
                    valueType = ValueType.Concated;

                    // Eat '.'.
                    reader.Read();
                }
                // Value range.
                else if(reader.Peek() == '-'){
                    // Range and conacted is not allowed to mix. Also multiple ranges not allowed.
                    if(valueType != ValueType.Single){
                        throw new ParseException("Invalid ABNF 'dec-val' value '" + reader.ReadToEnd() + "'.");
                    }
                    values.Add(Convert.ToInt32(b.ToString()));
                    b = new StringBuilder();
                    valueType = ValueType.Range;

                    // Eat '-'.
                    reader.Read();
                }
                // Not dec-val char, value reading completed.
                else{
                    // - or . without required 1 DIGIT.
                    if(b.Length == 0){
                        throw new ParseException("Invalid ABNF 'dec-val' value '" + reader.ReadToEnd() + "'.");
                    }
                    break;
                }
            }
            values.Add(Convert.ToInt32(b.ToString()));

            if(valueType == ValueType.Single){
                return new ABNF_DecVal(values[0],values[0]);
            }
            else if(valueType == ValueType.Concated){
                return new ABNF_DecVal(values.ToArray());
            }
            else{
                return new ABNF_DecVal(values[0],values[1]);
            }
        }


        #region Properties implementation

        #endregion
    }
}
